#include "etopshm.h"

ETOPSHM_T *etopshmaddr=NULL;
int etopshm_sem_id;
union semun
{
  int val;
  struct semid_ds *buf;
  unsigned short *array;
}etopshm_sem_union;

void etopshm_init(void)
{
	int shmid;
	struct shmid_ds buf;
	
	shmid = shmget(ETOPSHM_KEY,ETOPSHM_BLOCK_LEN,IPC_CREAT|0666);
	etopshmaddr = (ETOPSHM_T *)shmat(shmid,NULL,0);
	//printf("etopshm_init() at 0x%p,size %d,real struct size %d\n",etopshmaddr,size,sizeof(struct __data));
	etopshm_sem_init(ETOPSHM_SEM_KEY);
}

void set_all(ETOPSHM_T *etopshmaddr,char *name,void *value,int i,int type)
{
	char cValue;
	int iValue;
	char sValue[ETOPSHM_STR_LEN]="";
	etopshm_sem_p();
	if(type == CHAR_TYPE){
		strcpy(etopshmaddr->d.c[i].name,name);
		memcpy(&cValue,value,sizeof(char));
		etopshmaddr->d.c[i].v = cValue;
	}
	else if(type == INT_TYPE){
		strcpy(etopshmaddr->d.i[i].name,name);
		memcpy(&iValue,value,sizeof(int));
		etopshmaddr->d.i[i].v = iValue;
	}
	else if(type == STR_TYPE){
		strcpy(etopshmaddr->d.s[i].name,name);
		strcpy(etopshmaddr->d.s[i].v,value);
	}
	etopshm_sem_v();
}

void etopshm_set(int type,char *name,void *value)
{
	int i;
	char getname=0;
	
	if(!etopshmaddr){
		printf("etopshmaddr point error\n");
		return;
	}
	
	if(!strcmp(name,"")){
		printf("etopshm_set() name empty\n");
		return;
	}
	
	if(type == CHAR_TYPE){
		for(i=0;i<ETOPSHM_ITEM_CNT;i++){
			if(!strcmp(etopshmaddr->d.c[i].name,name)){
				set_all(etopshmaddr,name,value,i,CHAR_TYPE);
				break;
			}
			if(i==(ETOPSHM_ITEM_CNT-1))//final
				getname = 1;
		}
		if(getname == 1){
			for(i=0;i<ETOPSHM_ITEM_CNT;i++){
				if(!strcmp(etopshmaddr->d.c[i].name,"")){
					set_all(etopshmaddr,name,value,i,CHAR_TYPE);
					break;
				}
			}
		}
	}
	else if(type == INT_TYPE){
		for(i=0;i<ETOPSHM_ITEM_CNT;i++){
			if(!strcmp(etopshmaddr->d.i[i].name,name)){
				set_all(etopshmaddr,name,value,i,INT_TYPE);
				break;
			}
			if(i==(ETOPSHM_ITEM_CNT-1))//final
				getname = 1;
		}
		if(getname == 1){
			for(i=0;i<ETOPSHM_ITEM_CNT;i++){
				if(!strcmp(etopshmaddr->d.i[i].name,"")){
					set_all(etopshmaddr,name,value,i,INT_TYPE);
					break;
				}
			}
		}
	}
	else if(type == STR_TYPE){
		for(i=0;i<ETOPSHM_ITEM_CNT;i++){
			if(!strcmp(etopshmaddr->d.s[i].name,name)){
				set_all(etopshmaddr,name,value,i,STR_TYPE);
				break;
			}
			if(i==(ETOPSHM_ITEM_CNT-1))//final
				getname = 1;
		}
		if(getname == 1){
			for(i=0;i<ETOPSHM_ITEM_CNT;i++){
				if(!strcmp(etopshmaddr->d.s[i].name,"")){
					set_all(etopshmaddr,name,value,i,STR_TYPE);
					break;
				}
			}
		}
	}
}

int etopshm_get(int type,char *name,void *value)
{
	int i;
	char getname=0;
	
	if(!etopshmaddr){
		printf("etopshmaddr point error\n");
		return;
	}
	
	if(!strcmp(name,"")){
		printf("etopshm_get() name empty\n");
		return;
	}	
	
	if(type == CHAR_TYPE){
		for(i=0;i<ETOPSHM_ITEM_CNT;i++){
			if(!strcmp(etopshmaddr->d.c[i].name,name)){
				memcpy(value,&etopshmaddr->d.c[i].v,sizeof(char));
				return 1;
			}
			if(i==(ETOPSHM_ITEM_CNT-1)){
				printf("etopshm_get(%s) error\n",name);
				return -1;
			}
		}
	}
	else if(type == INT_TYPE){
		for(i=0;i<ETOPSHM_ITEM_CNT;i++){
			if(!strcmp(etopshmaddr->d.i[i].name,name)){
				memcpy(value,&etopshmaddr->d.i[i].v,sizeof(int));
				return 2;
			}
			if(i==(ETOPSHM_ITEM_CNT-1)){
				printf("etopshm_get(%s) error\n",name);
				return -2;
			}
		}
	}
	else if(type == STR_TYPE){
		for(i=0;i<ETOPSHM_ITEM_CNT;i++){
			if(!strcmp(etopshmaddr->d.s[i].name,name)){
				strcpy(value,etopshmaddr->d.s[i].v);
				return 3;
			}
			if(i==(ETOPSHM_ITEM_CNT-1)){
				printf("etopshm_get(%s) error\n",name);
				return -3;
			}
		}
	}
	
	return 0;
}

void etopshm_wipe(void)
{
	etopshm_sem_p();
	memset(etopshmaddr,0,sizeof(ETOPSHM_T));
	etopshm_sem_v();
}

void etopshm_dumpall(void)
{
	int i;
	
	printf("===== 1Byte =====\n");
	for(i=0;i<ETOPSHM_ITEM_CNT;i++){
		if(strcmp(etopshmaddr->d.c[i].name,""))
			printf("%s=%d\n",etopshmaddr->d.c[i].name,etopshmaddr->d.c[i].v);
	}
	printf("===== 4Byte =====\n");
	for(i=0;i<ETOPSHM_ITEM_CNT;i++){
		if(strcmp(etopshmaddr->d.i[i].name,""))
			printf("%s=%d\n",etopshmaddr->d.i[i].name,etopshmaddr->d.i[i].v);
	}
	printf("===== string =====\n");
	for(i=0;i<ETOPSHM_ITEM_CNT;i++){
		if(strcmp(etopshmaddr->d.s[i].name,""))
			printf("%s=%s\n",etopshmaddr->d.s[i].name,etopshmaddr->d.s[i].v);
	}
}

void etopshm_sem_init(int key)
{
	etopshm_sem_id = semget((key_t)key,1,0666 | IPC_CREAT);
	etopshm_sem_union.val=1;
	if (semctl(etopshm_sem_id,0,SETVAL,etopshm_sem_union)== -1)
    return;
}

int etopshm_sem_p(void)
{
	struct sembuf sem_b;
	sem_b.sem_num = 0;
  sem_b.sem_op = -1;
  sem_b.sem_flg = SEM_UNDO; //or IPC_NOWAIT, don't wait if unsuccessful
  if (semop(etopshm_sem_id,&sem_b,1) == -1)
		exit(EXIT_FAILURE);
  return 1;
}

int etopshm_sem_v(void)
{
	struct sembuf sem_b;
  sem_b.sem_num = 0;
  sem_b.sem_op = 1;
  sem_b.sem_flg = SEM_UNDO; //or IPC_NOWAIT, don't wait if unsuccessful
  if (semop(etopshm_sem_id,&sem_b,1) == -1)
		exit(EXIT_FAILURE);
  return 1;
}
